var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var config = require('config-lite')(__dirname);
var compress = require('compression');
var session = require('express-session');
var MongoStore = require('connect-mongo')(session);

var helpers = require('./helpers/index');



// Application() app对象一般用来表示Express程序。通过调用Express模块导出的顶层的express()方法来创建它
//app对象具有以下的方法：
// 路由HTTP请求；具体可以看app.METHOD和app.param这两个例子。
// 配置中间件；具体请看app.route。
// 渲染HTML视图；具体请看app.render。
// 注册模板引擎；具体请看app.engine。
var app = express();


var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
var adminRouter = require('./routes/admin');


// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

logger('short');


//app.use是express“调用中间件的方法”。所谓“中间件（middleware），就是处理HTTP请求的函数，用来完成各种特定的任务，
// 比如检查用户是否登录、分析数据、以及其他在需要最终将数据发送给用户之前完成的任务。”。这是阮一峰文章的原话。
// 简而言之，app.use() 里面使用的参数，主要是函数。但这个使用，并不是函数调用，而是使能的意思。
// 当用户在浏览器发出请求的时候，这部分函数才会启用，进行过滤、处理。

app.use(logger('dev'));
app.use(compress());

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public'),{maxAge: 864000}));
//app.use(express.static(path.join(__dirname, 'public')));


app.use(session({
  name: config.session.key,// 设置 cookie 中保存 session id 的字段名称
  secret: config.session.secret,// 通过设置 secret 来计算 hash 值并放在 cookie 中，使产生的 signedCookie 防篡改
  resave: true,// 强制更新 session
  saveUninitialized: true,// 设置为 false，强制创建一个 session，即使用户未登录
  cookie: {
    maxAge: config.session.maxAge// 过期时间，过期后 cookie 中的 session id 自动删除
  },
  store: new MongoStore({// 将 session 存储到 mongodb
    url: config.mongodb// mongodb 地址
  })
}));


// 添加模板必需的变量,这样在调用 res.render 的时候就不用传入这四个变量了，
  // express 为我们自动 merge 并传入了模板，所以我们可以在模板中直接使用这四个变量。
  // 没有挂载路径的中间件，应用的每个请求都会执行该中间件
  //locals是Express应用中 Application(app)对象和Response(res)对象中的属性，该属性是一个对象。该对象的主要作用是，将值传递到所渲染的模板中。
  //express/lib/response.js 源码
  // res.render = function render(view, options, callback) {
  //     var app = this.req.app;
  //     var opts = options || {};
  //     ...
  //     // merge res.locals
  //     opts._locals = self.locals;
  //     ...
  //     // render
  //     app.render(view, opts, done);
  // };
  // 可以看出：在调用 res.render 的时候，express 合并（merge）了 3 处的结果后传入要渲染的模板，
  // 优先级：res.render 传入的对象> res.locals 对象 > app.locals 对象，
  // 所以 app.locals 和 res.locals 几乎没有区别，都用来渲染模板，
  // 使用上的区别在于：
  // app.locals 上通常挂载常量信息（如博客名、描述、作者信息），
  // res.locals 上通常挂载变量信息，即每次请求可能的值都不一样（如请求者信息，res.locals.user = req.session.user）。


app.use(function (req, res, next) {
  res.locals.title = config.title;
  res.locals.describe = config.describe;
  res.locals.helpers = helpers;
  next();
});



app.use('/', indexRouter);
app.use('/users', usersRouter);
app.use('/admin', adminRouter);


// catch 404 and forward to error handler
app.use(function(req, res, next) {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use(function(err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});



module.exports = app;
